package org.example.controller;

import org.activiti.bpmn.BpmnAutoLayout;
import org.activiti.bpmn.model.Process;
import org.activiti.bpmn.model.*;
import org.activiti.engine.*;
import org.activiti.engine.impl.identity.Authentication;
import org.activiti.engine.impl.util.CollectionUtil;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.image.ProcessDiagramGenerator;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.apache.commons.io.FileUtils;
import org.example.bean.RejectTask;
import org.example.bean.WorkFlow;
import org.example.bean.WorkFlowNode;
import org.example.utils.ActivitiUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
public class ProcessController {
    @Autowired
    private RepositoryService repositoryService;  //流程定义和流程部署相关功能
    @Autowired
    private ProcessEngine processEngine;  //流程引擎

    @Resource
    TaskService taskService;


    @Autowired
    private ManagementService managementService;

    /**
     * 动态流程实例并输出png和xml
     *
     * @throws IOException
     */
    @GetMapping("/wf/deploy")
    public String createDeployment() throws IOException {

        //模拟前端页面数据
        WorkFlow workFlow = new WorkFlow(1, "test", "流程测试");

        List<WorkFlowNode> stepList = new ArrayList<>();
        List<Integer> childList1 = new ArrayList<>();
        childList1.add(2);
        WorkFlowNode s1 = new WorkFlowNode(1, workFlow.getId(), "start", 1, 1, childList1, null, null);

        List<Integer> childList2 = new ArrayList<>();
        childList2.add(3);
        childList2.add(4);
        WorkFlowNode s2 = new WorkFlowNode(2, workFlow.getId(), "parallelGateway-fork", 2, 2, childList2, null, "a");
        List<Integer> childList3 = new ArrayList<>();
        childList3.add(6);
        WorkFlowNode s3 = new WorkFlowNode(3, workFlow.getId(), "task1", 0, 3, childList3, null, "a");
        List<Integer> childList4 = new ArrayList<>();
        childList4.add(5);
        WorkFlowNode s4 = new WorkFlowNode(4, workFlow.getId(), "task2", 0, 4, childList4, null, "a");
        List<Integer> childList5 = new ArrayList<>();
        childList5.add(6);

        WorkFlowNode s5 = new WorkFlowNode(5, workFlow.getId(), "task22", 0, 5, childList5, null, "a");

        List<Integer> childList6 = new ArrayList<>();

        childList6.add(7);

        WorkFlowNode s6 = new WorkFlowNode(6, workFlow.getId(), "parallelGateway-join", 3, 6, childList6, null, "a");

        List<Integer> childList7 = new ArrayList<>();
        childList7.add(8);
        childList7.add(9);
        WorkFlowNode s7 = new WorkFlowNode(7, workFlow.getId(), "exclusiveGate", 4, 7, childList7, null, "a");
        List<Integer> childList8 = new ArrayList<>();
        childList8.add(10);
        WorkFlowNode s8 = new WorkFlowNode(8, workFlow.getId(), "task3", 0, 8, childList8, "${flag=='true'}", "a");
        List<Integer> childList9 = new ArrayList<>();
        childList9.add(10);
        WorkFlowNode s9 = new WorkFlowNode(9, workFlow.getId(), "task4", 0, 9, childList9, "${flag=='false'}", "a");
        List<Integer> childList10 = new ArrayList<>();
        childList10.add(11);
        WorkFlowNode s10 = new WorkFlowNode(10, workFlow.getId(), "receiveTask", 6, 10, childList10, null, "a");

        WorkFlowNode s11 = new WorkFlowNode(11, workFlow.getId(), "end", 5, 11, new ArrayList<>(), null, "a");
        stepList.add(s1);
        stepList.add(s2);
        stepList.add(s3);
        stepList.add(s4);
        stepList.add(s5);
        stepList.add(s6);
        stepList.add(s7);
        stepList.add(s8);
        stepList.add(s9);
        stepList.add(s10);
        stepList.add(s11);

        //创建ProcessEngine对象
        ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();

        //得到RepositoryService
        RepositoryService repositoryService = processEngine.getRepositoryService();

        // 1. 建立模型
        BpmnModel model = new BpmnModel();
        Process process = new Process();
        model.addProcess(process);
        process.setId(workFlow.getName());
        process.setName(workFlow.getName());
        stepList.forEach(step -> {
            if (step.getType() == 1) {
                process.addFlowElement(ActivitiUtil.createStartEvent());
            } else if (step.getType() == 5) {
                process.addFlowElement(ActivitiUtil.createEndEvent());
            } else if (step.getType() == 2 || step.getType() == 3) {
                process.addFlowElement(ActivitiUtil.createParallelGateway(step.getName(), step.getName()));
            } else if (step.getType() == 4) {
                process.addFlowElement(ActivitiUtil.createExclusiveGateway(step.getName(), step.getName()));
            } else if (step.getType() == 6) {
                process.addFlowElement(ActivitiUtil.createReceiveTask(step.getName(), step.getName()));
            } else {
                process.addFlowElement(ActivitiUtil.createUserTask(step.getName(), step.getName(), step.getAssignee()));
            }
        });

        //连线
        stepList.forEach(step -> {
            List<Integer> childList = step.getChlidOrderIds();
            childList.forEach(child -> {
                stepList.forEach(step1 -> {
                    if (step1.getOrderId().compareTo(child)==0) {
                        if (step.getType() == 4) {
                            process.addFlowElement(ActivitiUtil.createSequenceFlow(step.getName(), step1.getName(), step1.getConditionExpression()));
                        } else {
                            process.addFlowElement(ActivitiUtil.createSequenceFlow(step.getName(), step1.getName(), null));
                        }
                    }
                });
            });
        });

        //定义并设置流程变量
        Map<String, Object> variables = new HashMap<>();
        variables.put("flag", 1 == 2);
        //deploy
        Deployment deployment = repositoryService.createDeployment().addBpmnModel("process/dynamic-model.bpmn", model).name("Dynamic process deployment").deploy();
        System.out.println("deploymentId:"+deployment.getId());
        //start
        ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey(workFlow.getName(), variables);
        System.out.println("processInstanceId:" + processInstance.getId());
        System.out.println("getProcessDefinitionId:"+processInstance.getProcessDefinitionId());

        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        //save as  png
        new BpmnAutoLayout(bpmnModel).execute();
        List<String> highLightedActivities = processEngine.getRuntimeService().getActiveActivityIds(processInstance.getId());// 高亮节点
        List<String> highLightedFlows = new ArrayList<>(); // 高亮连接线
        ProcessDiagramGenerator processDiagramGenerator = new DefaultProcessDiagramGenerator();
        InputStream inputStream = processDiagramGenerator.generateDiagram(bpmnModel, "png", highLightedActivities, highLightedFlows, "宋体", "宋体", "宋体", null, 1.0);
        FileUtils.copyInputStreamToFile(inputStream, new File("E:\\process.png"));

        //save sa  xml
        InputStream inputStreamXml = processEngine.getRepositoryService().getResourceAsStream(deployment.getId(), "process/dynamic-model.bpmn");
        FileUtils.copyInputStreamToFile(inputStreamXml, new File("E:\\process.bpmn.xml"));
        return processInstance.getId();
    }

    //查看指定用户任务列表
    @GetMapping(value = "/wf/taskList/{usrId}")
    public List<Map<String, Object>> taskList(@PathVariable String usrId) {
        Authentication.setAuthenticatedUserId(usrId);
        //mjm 为流程定义中分配的人员 对应 processes/SimpleProcess.bpmn:5
        List<org.activiti.engine.task.Task>  taskList = taskService.createTaskQuery().taskCandidateOrAssigned(usrId).list();
        return taskList.stream().map(task -> {
            Map<String, Object> data = new HashMap<>();
          //  data = BeanUtil.copyProperties(task, Map.class, "execution", "processInstance", "variableInstances");
            return data;
        }).collect(Collectors.toList());
    }

    //完成任务
    @GetMapping(value = "/wf/completeTask/{usrId}/{processId}")
    public String completeTask(@PathVariable String usrId,@PathVariable String processId) {
        Authentication.setAuthenticatedUserId(usrId);
//        Authentication.setAuthenticatedUserId("王五");
        List<org.activiti.engine.task.Task> taskList = taskService.createTaskQuery().taskCandidateOrAssigned(usrId).processInstanceId(processId).list();
        if (CollectionUtil.isEmpty(taskList)) {
            throw new ActivitiObjectNotFoundException("processId:" + processId + "-Assignee:admin");
        }
        taskService.complete(taskList.get(0).getId());
        //mjm 为流程定义中分配的人员 对应 processes/SimpleProcess.bpmn:5
        return "操作完成!";
    }

    @GetMapping(value = "/wf/rejectTask/{usrId}/{processId}")
    public String rejectTask(@PathVariable String usrId,String processId) {
        Authentication.setAuthenticatedUserId(usrId);
//        Authentication.setAuthenticatedUserId("王五");
        List<org.activiti.engine.task.Task> taskList = taskService.createTaskQuery().taskCandidateOrAssigned(usrId).processInstanceId(processId).list();
        if (CollectionUtil.isEmpty(taskList)) {
            throw new ActivitiObjectNotFoundException("processId:" + processId + "-Assignee:admin");
        }
        managementService.executeCommand(new RejectTask(taskList.get(0).getId(),new HashMap<>(),"驳回"));
        return "操作完成!";
    }
}